package com.gzzyy.unionchain.communicate.webrtc

import android.util.Log
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
import com.gzzyy.unionchain.LiveEvent
import com.gzzyy.unionchain.communicate.webrtc.bean.ConnectChangeBean
import com.gzzyy.unionchain.communicate.webrtc.bean.ContactBean
import com.gzzyy.unionchain.communicate.webrtc.bean.IdReportBean
import com.jeremyliao.liveeventbus.LiveEventBus
import io.socket.client.IO
import io.socket.client.Socket
import io.socket.emitter.Emitter
import java.net.URISyntaxException

class SignalingClient(private val signalingListener: SignalingListener) {
    companion object {
        private val TAG = SignalingClient::class.java.simpleName
        const val INIT = "init"
        const val OFFER = "offer"
        const val ANSWER = "answer"
        const val CANDIDATE = "candidate"
    }

    private val socketAddress = "http://47.114.58.183:9501"

    private var clientId = ""
    private var socket: Socket? = null

    private val connectListener = Emitter.Listener { args ->
        Log.i(TAG, "I have connected to server call ${socket?.id()}")
        val message = JSONObject()
        message["requestUid"] = socket?.id()
        clientId = socket?.id() ?: ""
        LiveEventBus.get(LiveEvent.UpdateMyUuid).post(clientId)
        socket?.emit(SignalingEvent.IdRequest.name, message.toJSONString())
    }
    private val disconnectListener = Emitter.Listener { args ->
        Log.i(TAG, "I have disconnected to server.")
        clientId = ""
        //todo 通知外部与信令服务器连接已断开
    }
    private val idReportListener = Emitter.Listener { args ->
        val jsonStr = args[0] as String
        val idReportBean = JSON.parseObject(jsonStr, IdReportBean::class.java)
        Log.i(TAG, "idReportListener call: ${idReportBean.requestId}")
        if (idReportBean.requestId == socket?.id()) {
            if (!idReportBean.uuids.isNullOrEmpty()) {
                Log.i(TAG, "uuids size = " + idReportBean.uuids.size)
                LiveEventBus.get(LiveEvent.ContactBatchUpdate).post(idReportBean)
                //逐个发送初始化消息，开启webRtc连接
                for (id in idReportBean.uuids) {
                    sendInitMsg(id)
                }
            }
        }
    }
    private val connectMsgListener = Emitter.Listener { args ->
        val dataStr = args[0] as String
        val data = JSONObject.parseObject(dataStr)
        Log.d(TAG, "messageListener call data : $data")
        val from = data.getString("from")
        val type = data.getString("type")
        var payload: JSONObject? = null
        if (type != INIT) {
            payload = data.getJSONObject("payload")
        }
        signalingListener.onReceiveSignaling(type, from, payload)
    }
    private val connectChangeListener = Emitter.Listener { args ->
        Log.d(TAG, "connectChangeListener call data ")
        val jsonStr = args[0] as String?
        if (jsonStr != null) {
            val connectChangeBean =
                JSON.parseObject(jsonStr, ConnectChangeBean::class.java)
            if (clientId != connectChangeBean.uid) {
                LiveEventBus.get(LiveEvent.ContactUpdate)
                    .post(ContactBean(connectChangeBean.uid, connectChangeBean.isConnect))

                if (connectChangeBean.isConnect) {
                    //发送初始化消息，以启动webRtc 连接，todo 考虑放入协程中
                    sendInitMsg(connectChangeBean.uid)
                } else {
                    //
                }
            }
        }
    }

    init {
        try {
            socket = IO.socket(socketAddress)
            Log.d(TAG, "client create")
            socket?.on(Socket.EVENT_CONNECT, connectListener)
                ?.on(Socket.EVENT_DISCONNECT, disconnectListener)
                ?.on(SignalingEvent.IdReport.name, idReportListener)
                ?.on(SignalingEvent.ConnectTo.name, connectMsgListener)
                ?.on(SignalingEvent.ConnectChange.name, connectChangeListener)
            socket?.connect()
        } catch (e: URISyntaxException) {
            Log.e(TAG, "URISyntaxException when client create")
        }
    }

    /**
     * 向信令服务器发消息
     *
     * @param to      id of recipient
     * @param type    type of message
     * @param payload payload of message
     */
    fun sendMessage(to: String, type: String, payload: String) {
        val message = JSONObject()
        message["from"] = clientId
        message["to"] = to
        message["type"] = type
        message["payload"] = payload
        socket?.emit(SignalingEvent.ConnectTo.name, message.toString())
    }

    private fun sendInitMsg(to: String) {
        sendMessage(to, "init", "")
    }

    interface SignalingListener {
        fun onReceiveSignaling(type: String, fromUid: String, payload: JSONObject?)
    }
}